#include <iostream>
#include <vector>
using namespace std;
#include "SymTable.h"

SymTable* SymTable::myInstance;

// Returns the symbol table singleton instance.
SymTable * SymTable::getMyInstance(void)
{
	if( NULL == myInstance )
		myInstance = new SymTable();
	return myInstance;
}

// Destroy the Singleton instance.
void SymTable::destroyMyInstance(void)
{
	if( NULL != myInstance )
	{
		delete myInstance;
		myInstance = NULL;
	}
}

// Create a symbol table entry
int SymTable::insert(const char *s, int token)
{
	Entry *entry = new Entry();
	entry->token = token;
	entry->lexemme = new string(s);
	entries.push_back(entry);
	return (entries.size() - 1); 
}

// return the index for the lexemme with name s
int SymTable::lookup(const char *s)
{
	for( int iEntry = 0; iEntry < entries.size(); iEntry++ )
	{	
		if( 0 == entries[iEntry]->lexemme->compare(s) )
			return iEntry;
	}  
	return -1;
}

// returns token for the stored at index int symbol table 
int SymTable::tokenForEntryAtIndex(int index)
{
	if( ( index >= 0 ) && ( index < entries.size() ) )
		return entries[index]->token;
	else
		return -1;
}

// returns value of the identifier stored at a particular index
int SymTable::ValueForEntryAtIndex(int index)
{
	if( ( index >= 0 ) && ( index < entries.size() ) )
		return entries[index]->attrib.val;
	else
		return -1;
}

// returns identifier name at particular symbol table index
const char* SymTable::lexemmeForEntryAtIndex(int index)
{
	if( ( index >= 0 ) && ( index < entries.size() ) )
        return entries[index]->lexemme->c_str();
    else
        return NULL;	
}

// To delete symbol table entry at a particular index
int SymTable::deleteEntryAtIndex(int index)
{
	if( (index < 0) && ( index >= entries.size() ) )
		return -1;	
	entries.erase(entries.begin() + index);
	return 0;
}

// To delete range of entries from symbol table
int SymTable::deleteEntriesInRange(int start, int end)
{
	if( end < start )
		return  -1;
	if( (start < 0) || (end >= entries.size()) )
		 return -1;
	entries.erase(entries.begin() + start, entries.begin() + end);
	return 0;
}

// return the value of the counter
int SymTable::getCounter(void)
{
	return counter;
}

// To Initialize counter to 0
void SymTable::setCounter(int newCounter)
{
	counter = newCounter;
}

// Generates all possible combination of bool values for identifier seen so far in the input expression.
int SymTable::generate(void)
{ 
	int max = 1 << entries.size(), iEntry = 0, tempCounter = counter;
	if( counter >= max )
		return -1;
	for( iEntry = 0; iEntry < entries.size(); iEntry++)
		entries[iEntry]->attrib.val = 0;
	iEntry = 0;
	while(tempCounter != 0)
	{
		entries[iEntry]->attrib.val = tempCounter % 2;
		tempCounter = tempCounter / 2;
		iEntry++;
	}
	counter++;
}

// Prints the content of the symbol table
void SymTable::print(void)
{
	cout << "Entries in symbol table are:" << endl;
	vector<Entry *>::iterator it = entries.begin();
	while(it != entries.end())
	{
		cout << ((*it)->lexemme)->c_str() << " " << (*it)->attrib.val << " " << (*it)->token << endl;
		it++;
	}	
	cout << endl;
}

